import MyUtils from './calc'
import { differenceBy, sumBy } from 'lodash-es'
import { myCalc, arral, GetVotetype, MaxJiangjin } from './counterFun'

export const pmTable = {
    mnl: 'SportteryWL', // 胜负
    hdc: 'SportteryHWL', // 让分胜负
    hilo: 'SportteryBS', // 大小分
    wnm: 'SportteryWS', // 胜分差
}
// 将 “周三” 转为 3
export function transWeekToNum(week) {
    switch (week.slice(1)) {
        case '一':
            return '1';
        case '二':
            return '2';
        case '三':
            return '3';
        case '四':
            return '4';
        case '五':
            return '5';
        case '六':
            return '6';
        case '日':
            return '7';
    }
}
// 转换串关数据为一维数组
export function transChuanType(data) {
    let arr = []
    for (let gg of data) {
        const item = GetVotetype(gg.replace('*', '_'))
        arr = arr.concat(item.split(' '))
    }
    return arr.map(item => Number(item));
}
// 根据所选玩法获取最大值和最小值数据
function computerMax(mnl, hdc, hilo, wnm, mrq) {
    let aMax = 0, nnm = 0, aMaxArr = [],
        sfHome = null, sfAway = null, // 胜负主客最大值
        rfsfHome = null, rfsfAway = null, // 让分胜负主客最大值
        dxfMax = null, // 大小分最大值
        pmNum = 0; // 所选玩法存在的个数
    const rq = Math.abs(mrq), realRq = Number(mrq); // 让球数 （-6.5是主队让球）（+6.5是客队让球）
    const pmObjMinArr = []; // 各个玩法的最小值数组
    if (mnl) { // 胜负玩法存在
        sfHome = mnl.find(item => item.play.includes('win'));
        sfAway = mnl.find(item => item.play.includes('lose'));
        pmObjMinArr.push(mnl.sort((a, b) => Number(a.odds) - Number(b.odds))[0]);
        pmNum++;
    }
    if (hdc) { // 让分胜负玩法存在
        rfsfHome = hdc.find(item => item.play.includes('hdc_win'));
        rfsfAway = hdc.find(item => item.play.includes('hdc_lose'));
        pmObjMinArr.push(hdc.sort((a, b) => Number(a.odds) - Number(b.odds))[0]);
        pmNum++;
    }
    if (hilo) { // 大小分玩法
        pmNum++;
        const dxfSort = hilo.sort((a, b) => Number(a.odds) - Number(b.odds)); // 从小到大升序排列
        dxfMax = dxfSort[dxfSort.length - 1];
        pmObjMinArr.push(dxfSort[0]);
    }
    let obj = {};
    if (wnm) { // 胜分差玩法存在
        pmNum++;
        pmObjMinArr.push(wnm.sort((a, b) => Number(a.odds) - Number(b.odds))[0]);
        const sfcCombMax = wnm.map(item => {
            let rfsfArr = [];
            if (item.play.includes('hw')) {
                const range = item.play.replace('hw', '').split('_');
                const minLimit = Number(range[0]), maxLimit = Number(range[1]);
                // 获取比分差和让分之间的关联
                if (realRq < 0) { // 主队让球 -6.5
                    if (rq < minLimit) {
                        // 取让分主胜 1
                        rfsfArr = [rfsfHome];
                    } else {
                        rfsfArr = (rq > maxLimit)
                            ? [rfsfAway] // 取让分 客胜 0
                            : [rfsfHome, rfsfAway]; // 让分 主胜 客服都取 [0,1]
                    }
                } else { // 客队让球
                    // 取让分主胜 1
                    rfsfArr = [rfsfHome];
                }
                aMaxArr = [sfHome, ...rfsfArr, dxfMax, item].filter(item => !!item);
            } else {
                const range = item.play.replace('gw', '').split('_');
                const minLimit = Number(range[0]), maxLimit = Number(range[1]);
                if (realRq > 0) { // 客队让球 +6.5
                    if (rq < minLimit) {
                        // 取让分客胜 0
                        rfsfArr = [rfsfAway];
                    } else {
                        rfsfArr = (rq > maxLimit)
                            ? [rfsfHome] //取让分主胜 1
                            : [rfsfHome, rfsfAway]; // 让分 主胜 客服都取 [0,1]
                    }
                } else {
                    //取让分客胜 0
                    rfsfArr = [rfsfAway];
                }
                aMaxArr = [sfAway, ...rfsfArr, dxfMax, item].filter(item => !!item);
            }
            nnm = aMaxArr.length;
            aMax = aMaxArr.reduce((p, c) => Number(p) + Number(c.odds), 0)
            return { aMaxArr, nnm, aMax };
        }).sort((a, b) => b.aMax - a.aMax);
        // 获取胜分差跟其他玩法混合后的最大值
        obj = sfcCombMax[0];
    } else {
        let combMax = []
        if (sfHome && sfAway) {
            // 主胜和客胜都有的情况下 比主客最大值
            const home = Number(sfHome.odds) + Number(rfsfHome ? rfsfHome.odds : 0);
            const away = Number(sfAway.odds) + Number(rfsfAway ? rfsfAway.odds : 0);
            combMax = home > away ? [sfHome, rfsfHome] : [sfAway, rfsfAway];
        } else if (sfHome || sfAway) {
            if (realRq < 0) { // 主队让球
                // 主胜  让球的情况下可能主胜也可能客胜
                // 客胜  让球的情况下只能客胜
                if (sfHome) {
                    const h1 = Number(sfHome.odds) + Number(rfsfHome ? rfsfHome.odds : 0);
                    const h2 = Number(sfHome.odds) + Number(rfsfAway ? rfsfAway.odds : 0);
                    combMax = h1 > h2 ? [sfHome, rfsfHome] : [sfHome, rfsfAway];
                } else if (sfAway) {
                    combMax = [sfAway, rfsfAway]
                }
            } else { // 客队让球
                // 主胜  让球的情况下只能主胜
                // 客胜  让球的情况下可能主胜也可能客胜
                if (sfHome) {
                    combMax = [sfHome, rfsfHome]
                } else if (sfAway) {
                    const rfsfHomeOdds = Number(rfsfHome ? rfsfHome.odds : 0);
                    const rfsfAwayOdds = Number(rfsfAway ? rfsfAway.odds : 0);
                    combMax = (rfsfHomeOdds > rfsfAwayOdds) ? [sfAway, rfsfHome] : [sfAway, rfsfAway];
                }
            }
        } else {
            // 未选择胜负玩法的情况
            const rfsfHomeOdds = Number(rfsfHome ? rfsfHome.odds : 0);
            const rfsfAwayOdds = Number(rfsfAway ? rfsfAway.odds : 0);
            combMax = (rfsfHomeOdds > rfsfAwayOdds) ? [rfsfHome] : [rfsfAway];
        }
        combMax.push(dxfMax);
        const aMaxArr = combMax.filter(item => !!item)
        nnm = aMaxArr.length;
        aMax = aMaxArr.reduce((p, c) => Number(p) + Number(c.odds), 0)
        obj = { aMaxArr, nnm, aMax};
    }
    return { ...obj, pmObjMinArr: pmObjMinArr.map(item => ({ ...item, odds: Number(item.odds) })), pmNum };
}
// 根据所选比赛获取需要的数据
export function getMinMaxNeedData(selectMatch) {
    const arr = []
    for (const match of selectMatch) { // 先循环比赛场次
        const { nnm, aMax, pmObjMinArr, pmNum } = computerMax(match.mnl, match.hdc, match.hilo, match.wnm, match.rq);
        arr.push({
            ...match,
            min: pmObjMinArr.sort((a, b) => a.odds - b.odds)[0],
            aMax, nnm, pmNum
        })
    }
    return arr;
}
/**
 * 篮球奖金评测：获取命中数的最小金额和最大金额
 * @param selectMatch {Array} 选中的比赛
 * @param chuan {Array} 选择的（N串1）的串关方式
 * @param mcn {Array} 选择的（M串N）的多串方式
 * @param multiple {Number} bet倍数
 */
export function basktBallBonusTest(selectMatch, chuan, mcn, multiple = 1, onlyMax = false) {
    const arr = getMinMaxNeedData(selectMatch)
    const maxSortArr = arr.slice().sort((a, b) => b.aMax - a.aMax); // 降序
    const rate = 2 * multiple;
    // 处理选中的串关数据为真实的串关数组
    const realChuan = transChuanType(chuan);
    if (onlyMax){
        let max = 0;
        for (const chuanNum of realChuan) { // 循环串关方式
            const evt = (mcn.length > 0 && chuanNum < selectMatch.length);
            const maxErArr = MyUtils.getNumbers(maxSortArr, chuanNum, false) // 二维数组，所有的组
            for (let comb of maxErArr) { // 循环最大组合
                var len = evt ? sumBy(differenceBy(arr, comb, 'matchId'), 'pmNum') : 1;
                const val = comb.reduce((prev, current) => {
                    return {
                        aMax: prev.aMax * current.aMax,
                        nnm: prev.nnm * current.nnm,
                    }
                })
                const limit = MaxJiangjin[chuanNum] * val.nnm; // 限额
                max += (val.aMax > limit ? limit : val.aMax) * len
            }
        }
        return max*rate;
    }else{
        const minSortArr = arr.slice().sort((a, b) => a.min.odds - b.min.odds); // 升序
        const hitArr = [];
        for (const chuanNum of realChuan) { // 循环串关方式
            // 如果选择M串N的多串方式，转化后的串关小于比赛场数需要补当前组合存在的次数
            const needOffsetTimes = (mcn.length > 0 && chuanNum < selectMatch.length);
            // if (chuanNum == 1) break;
            for (let i = chuanNum; i < (arr.length + 1); i++) { // 循环命中场次(i)
                // 命中场次为i
                const minErArr = MyUtils.getNumbers(minSortArr.slice(0, i), chuanNum, false) // 二维数组，所有的组合
                const maxErArr = MyUtils.getNumbers(maxSortArr.slice(0, i), chuanNum, false) // 二维数组，所有的组合
                // const evt = (needOffsetTimes && i !== chuanNum); // 是否参与补偿次数的条件
                const evt = needOffsetTimes;
                let min = 0, max = 0;
                for (let comb of minErArr) { // 循环最小组合
                    const len = evt ? sumBy(differenceBy(arr, comb, 'matchId'), 'pmNum') : 1;
                    const val = comb.reduce((prev, current) => {
                        return typeof (prev) === 'number' ? (prev * current.min.odds) : (prev.min.odds * current.min.odds)
                    })
                    min += (val > MaxJiangjin[chuanNum] ? MaxJiangjin[chuanNum] : val) * len;
                }
                for (let comb of maxErArr) { // 循环最大组合
                    const len = evt ? sumBy(differenceBy(arr, comb, 'matchId'), 'pmNum') : 1;
                    const val = comb.reduce((prev, current) => {
                        return {
                            aMax: prev.aMax * current.aMax,
                            nnm: prev.nnm * current.nnm,
                        }
                    })
                    const limit = MaxJiangjin[chuanNum] * val.nnm; // 限额
                    max += (val.aMax > limit ? limit : val.aMax) * len;
                }
                const minBouns = (min * rate), maxBouns = (max * rate);
                const findIndex = hitArr.findIndex(item => item.hitnum === i);
                if (findIndex > -1) {
                    hitArr[findIndex].minBouns += minBouns
                    hitArr[findIndex].maxBouns += maxBouns
                } else {
                    hitArr.push({ hitnum: i, minBouns, maxBouns });
                }
            }
        }
        return hitArr
    }
}

export function createCombDanTuo(dan, maxTuoArr, minTuoArr, chuans, multiple = 1) {
    const rate = 2 * multiple;
    let min = 0, max = 0;
    for (const chuanNum of chuans) { // 循环串关方式
        if (dan.length == Number(chuanNum)) {
            // arr.push(dan)
            const val = dan.reduce((prev, current) => {
                return { aMax: prev.aMax * current.aMax, nnm: prev.nnm * current.nnm, min: (prev.min * current.min.odds) }
            }, { aMax: 1, nnm: 1, min: 1 });
            const limit = MaxJiangjin[chuanNum] * val.nnm; // 限额
            max += (val.aMax > limit ? limit : val.aMax);
            min += (val.min > MaxJiangjin[chuanNum] ? MaxJiangjin[chuanNum] : val.min);
        } else if (dan.length < chuanNum) { // 4场比赛 2串1 1个胆
            const tuoNum = chuanNum - dan.length // 构成2串1 需要几个拖
            const minTuoComb = MyUtils.getNumbers(minTuoArr, tuoNum, false); // 取出所需tuoNum的拖组合
            for (const comb of minTuoComb) {
                const danTuo = [...dan, ...comb];
                // arr.push(danTuo);
                const val = danTuo.reduce((prev, current) => {
                    return typeof (prev) === 'number' ? (prev * current.min.odds) : (prev.min.odds * current.min.odds)
                })
                min += (val > MaxJiangjin[chuanNum] ? MaxJiangjin[chuanNum] : val);
            }
            const maxTuoComb = MyUtils.getNumbers(maxTuoArr, tuoNum, false); // 取出所需tuoNum的拖组合
            for (const comb of maxTuoComb) {
                const danTuo = [...dan, ...comb];
                // arr.push(danTuo);
                const val = danTuo.reduce((prev, current) => {
                    return {
                        aMax: prev.aMax * current.aMax,
                        nnm: prev.nnm * current.nnm,
                    }
                })
                const limit = MaxJiangjin[chuanNum] * val.nnm; // 限额
                max += (val.aMax > limit ? limit : val.aMax);
            }
            // const danTuoComb = tuoComb.map(comb => [...dan, ...comb]);
        }
        // console.log(333, `拖命中${maxTuoArr.length}, ${chuanNum}串1的拖胆组合`, min * rate, max * rate)
    }
    return { min: min * rate, max: max * rate }
}

function combDanTuoMaxBonus(dan, maxTuoArr, chuans, multiple = 1){
    const rate = 2 * multiple;
    let max = 0;
    for (const chuanNum of chuans) { // 循环串关方式
        if (dan.length == Number(chuanNum)) {
            const val = dan.reduce((prev, current) => {
                return { aMax: prev.aMax * current.aMax, nnm: prev.nnm * current.nnm }
            }, { aMax: 1, nnm: 1});
            const limit = MaxJiangjin[chuanNum] * val.nnm; // 限额
            max += (val.aMax > limit ? limit : val.aMax);
        } else if (dan.length < chuanNum) { // 4场比赛 2串1 1个胆
            const tuoNum = chuanNum - dan.length // 构成2串1 需要几个拖
            const maxTuoComb = MyUtils.getNumbers(maxTuoArr, tuoNum, false); // 取出所需tuoNum的拖组合
            for (const comb of maxTuoComb) {
                const danTuo = [...dan, ...comb];
                const val = danTuo.reduce((prev, current) => {
                    return {
                        aMax: prev.aMax * current.aMax,
                        nnm: prev.nnm * current.nnm,
                    }
                })
                const limit = MaxJiangjin[chuanNum] * val.nnm; // 限额
                max += (val.aMax > limit ? limit : val.aMax);
            }
        }
    }
    return max * rate
}

// 篮球奖金优化所需数据
export function optNeedData(orderData, chuans) {
    const arr = orderData;
    const realChuan = transChuanType(chuans);
    let zuhe = [], possibleComb = [];
    for (const chuanNum of realChuan) { // 循环串关方式
        const combErArr2 = MyUtils.getNumbers(arr, chuanNum, false)
        let combErArr = []
        for (const item of combErArr2){
            combErArr = combErArr.concat(arral(item))
        }
        const chuanItem = combErArr.map(comb => {
            return comb.map(select => {
                const isDxf = (select.type == 'hilo');
                const isRfsfAndDxf = (select.type == 'hdc' || isDxf); // 让分胜负和大小分
                return [
                    select.home, // 队伍名称 nameIndex
                    isDxf ? String(select.mid) : String(Number(select.rq)), // 让球 或者 中间数
                    Number(select.odds), // 赔率
                    select.result, // 所选玩法中文名称
                    isRfsfAndDxf ? Number(`-${select.odds}`) : Number(select.odds), // 赔率
                    pmTable[select.type], // 玩法名称代号 从玩法对照表中取出
                    select.weekNum.charAt(0) == '0' ? ('7' + select.weekNum.slice(1)) : select.weekNum, // 比赛代码 周日是0需要转换为7
                    // Number(select.odds) < select.aMax ? false : true, // 获取赔率最大值,是否参与计算最大奖金 true false,
                    select.guest, // 客队名称
                    select.matchId,
                    select.play,
                ];
            })
        })
        zuhe = zuhe.concat(chuanItem);
    }
    // 记录所有比赛内存在的玩法
    let pmArr = []
    for (const match of orderData) { // 循环比赛
        const mArr = []; // 同一场比赛内的所有选择的项
        for (const item of match) {
            const pm = item.type;
            const weekNum = item.weekNum.charAt(0) == '0' ? ('7' + item.weekNum.slice(1)) : item.weekNum
            if (!pmArr.includes(pm)) {
                pmArr.push(pm);
            }
            mArr.push(`${weekNum}@${pmTable[pm]}@${item.result}`);
        }
        possibleComb.push(mArr);
    }
    /*for (const item of selectMatch) { // 这里循环的selectMatch是基于raceColor
        const pmTableArr = Object.keys(pmTable)
        const weekNum = item.weekNum.charAt(0) == '0' ? ('7' + item.weekNum.slice(1)) : item.weekNum
        for (const pm of pmTableArr){
            if (item[pm]){
                if (!pmArr.includes(pm)) pmArr.push(pm);
                const str = item[pm].map(pi => `${weekNum}@${pmTable[pm]}@${pi.result}`);
                possibleComb.push(str);
            }
        }
    }*/
    // 是否混合多种玩法（只要所有比赛存在不同玩法就是mixed）
    const isMixed = pmArr.length > 1;
    const parame = {
        canHot: true,
        changshu: orderData.length, // 选择了几场比赛
        guoguan: chuans.map(gg => gg.replace('*', '_')), // ['2_1','3_1']
        lottery: "basketball",
        money: zuhe.length * 2, // totalMoney.value 包含元不适用
        type: isMixed ? 'mixed' : 'single', // single mixed
        zuhe,
    }
    return { parame, possibleComb: arral(possibleComb) };
}

export class Basktball {
    constructor(chuan, selectMatch, multiNum = 1) {
        this.chuan = chuan;
        this.chuanArr = this.transChuanType(chuan)
        this.selChuanArr = [];
        this.mcn = [];
        this.selectMatch = selectMatch;
        this.choose_len = selectMatch.length;
        this.multiNum = multiNum;
        this.dans = [];
    }
    transChuanType(data) { // 转换串关方式 并获取其中的多串
        let arr = [];
        const cm = []; // cm串M最小过关数
        for (let gg of data) {
            const cg = gg.replace('*', '_')
            const item = GetVotetype(cg)
            arr = arr.concat(item.split(' '))
            if (cg.split('_')[1] !== '1'){
                cm.push(cg);
            }
        }
        // 计算 串M最小过关数
        let cmMin = 0
        if (cm.length) {
            const cmsort = cm.map(item => GetVotetype(item).split(' ')).flat().sort()
            cmMin = Number(cmsort[0])
        }
        let cMin = 0
        // 计算 所有串关中的最小过关数
        if(arr.length){
            cMin = Number(arr.sort()[0])
        }
        this.selChuanArr = [cMin, cmMin]
        this.mcn = cm;
        return arr;
    }
    updateMult(multiNum) { // 更改倍数
        this.multiNum = multiNum;
        // 重新返回当前最高奖金
        return this.getMaxBonus();
    }
    updateChuan(chuan) { // 更新串关方式
        this.chuan = chuan;
        this.chuanArr = this.transChuanType(chuan)
    }
    updateChoose(chuan, selectMatch) { // 更新选中的比赛
        this.chuan = chuan;
        this.chuanArr = this.transChuanType(chuan)
        this.selectMatch = selectMatch;
        this.choose_len = selectMatch.length;
    }
    setDan(dans) {
        this.dans = dans;
    }
    // 获取总注数
    getZhuShu() {
        let sa = [], sb = [] // sb 胆码数组
        const pmArr = ['mnl', 'hdc', 'hilo', 'wnm'];
        for (const item of this.selectMatch) {
            let tp = []
            for (const pm of pmArr){
                if (item[pm]){
                    tp.push(`${pm}-${item[pm].length}-${item.weekNum}`)
                }
            }

            if (this.dans.includes(item.weekNum)) {
                sb.push(tp)
            } else {
                sa.push(tp)
            }
        }
        let zhushu = 0
        for (const ggWay of this.chuan) { // 循环串关
            zhushu += myCalc(ggWay, sa, sb)
        }
        return zhushu;
    }
    // 最高奖金
    getMaxBonus() {
        if (this.dans.length > 0) {
            return this.danTest(true).toFixed(2);
        } else {
            return basktBallBonusTest(this.selectMatch, this.chuan, this.mcn, this.multiNum, true).toFixed(2)
        }
    }
    // 奖金评测
    bonusTest() {
        return basktBallBonusTest(this.selectMatch, this.chuan, this.mcn, this.multiNum)
    }

    // 定胆评测
    danTest(onlyMax = false) {
        // const chuanArr = transChuanType(this.chuan)
        const arr = getMinMaxNeedData(this.selectMatch);
        const a = [], b = []; // a是拖码 b是胆码
        for (const item of arr) {
            this.dans.includes(item.weekNum) ? b.push(item) : a.push(item);
        }
        if (onlyMax){
            return combDanTuoMaxBonus(b, a, this.chuanArr, this.multiNum)
        }else{
            const aMax = a.slice().sort((a, b) => a.aMax - b.aMax), // 从小到大排列
                aMin = a.slice().sort((a, b) => b.min.odds - a.min.odds); // 从大到小排列
            // 先进行胆命中组合
            const danList = [], danNum = b.length;
            const minChuan = this.chuanArr.sort()[0];
            for (let i = 0; i <= a.length; i++) {
                const tuo = aMax.slice(i);
                if (danNum + tuo.length < minChuan) break;
                const { min, max } = createCombDanTuo(b, tuo, aMin.slice(i), this.chuanArr, this.multiNum) // 最大
                danList.push({ danNum, tuoNum: tuo.length, minMoney: min, maxMoney: max });
            }
            return danList;
        }
    }

    // 奖金优化
    bonusOpt(orderData) {
        return optNeedData(orderData, this.chuan)
        // return optNeedData(orderData, this.chuan, this.selectMatch)
    }

    destroy() {
        // 清除所有内部引用（如果有的话）
    }
}
